﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Diagnostics;

namespace Chaow.Sample {
    public partial class SampleForm : Form {
        public SampleForm() {
            InitializeComponent();
        }

        private void SampleForm_Load(object sender, EventArgs e) {
            loadFile(AppDomain.CurrentDomain.BaseDirectory + "Test.cs");
        }
        void loadFile(string path) {
            TreeNode ns, cls, mthd;
            foreach (string[] found in SourceReader.Read(path)) {
                if (!treeView1.Nodes.ContainsKey(found[0]))
                    ns = treeView1.Nodes.Add(found[0], found[0], 0, 0);
                else
                    ns = treeView1.Nodes[found[0]];
                if (!ns.Nodes.ContainsKey(found[1]))
                    cls = ns.Nodes.Add(found[1], found[1], 1, 1);
                else
                    cls = ns.Nodes[found[1]];
                mthd = cls.Nodes.Add(found[2], found[2], 2, 2);
                mthd.Tag = found[3];
            }
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) {
            if (e.Node.Tag == null)
                return;
            fillCode((string)e.Node.Tag);
            execute(e.Node);
        }
        const string Keyword = "abstract|event|new|struct|as|explicit|null|switch|base|extern|object|this|bool|false|operator|throw|break|finally|out|true|byte|fixed|override|try|case|float|params|typeof|catch|for|private|uint|char|foreach|protected|ulong|checked|goto|public|unchecked|class|if|readonly|unsafe|const|implicit|ref|ushort|continue|in|return|using|decimal|int|sbyte|virtual|default|interface|sealed|volatile|delegate|internal|short|void|do|is|sizeof|while|double|lock|stackalloc|else|long|static|enum|namespace|string|from|get|group|into|join|let|orderby|partial|select|set|value|where|yield";
        void fillCode(string code) {
            richTextBox1.Text = code;
            Regex kw = new Regex(@"(                #any of
                (?'comment'//.*\n)|                 #- single line comment
                (?'comment'/\*([^*]|\*(?!/))*\*/)|  #- multi line comment
                (?'string''[^']+')|                 #- char
                (?'string'""([^""]|(?<=\\)"")*"")|  #- string
                (?'string'@""([^""]|"""")*"")|      #- @string
                (?'keyword'\b(" + Keyword + @")\b)| #- keyword
                (?'class'(?<!\.)\b[\p{Lu}][\w]*\b)) #- class"
                , RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
            foreach (Match m in kw.Matches(code)) {
                if (m.Groups["comment"].Success) {
                    richTextBox1.Select(m.Index, m.Length);
                    richTextBox1.SelectionColor = Color.Green;
                } else if (m.Groups["string"].Success) {
                    richTextBox1.Select(m.Index, m.Length);
                    richTextBox1.SelectionColor = Color.Brown;
                } else if (m.Groups["keyword"].Success) {
                    richTextBox1.Select(m.Index, m.Length);
                    richTextBox1.SelectionColor = Color.Blue;
                } else {
                    richTextBox1.Select(m.Index, m.Length);
                    richTextBox1.SelectionColor = Color.FromArgb(43, 145, 175);
                }
            }
        }
        void execute(TreeNode node) {
            Type type = Type.GetType(string.Format("{0}.{1}", node.Parent.Parent.Name, node.Parent.Name));
            MethodInfo method = type.GetMethod(node.Name, BindingFlags.Public | BindingFlags.Static);

            using (StringWriter writer = new StringWriter()) {
                TextWriter old = Console.Out;
                Console.SetOut(writer);
                try {
                    Stopwatch timer = new Stopwatch();
                    timer.Start();
                    method.Invoke(null, null);
                    timer.Stop();
                    Console.WriteLine(timer.Elapsed);
                } catch {
                    Console.WriteLine("Error!");
                }
                textBox1.Text = writer.ToString();
                Console.SetOut(old);
            }
        }
    }
}
